package com.ibeeking.found.cop.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.common.entity.CurrentUser;
import com.ibeeking.found.common.enums.AddOrLessEnum;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.cop.b.rest.service.IGroupService;
import com.ibeeking.found.cop.b.rest.service.IGroupTagsService;
import com.ibeeking.found.cop.service.common.constants.FriendsConstant;
import com.ibeeking.found.cop.service.common.dos.GroupTagsDO;
import com.ibeeking.found.cop.service.common.dos.GroupTagsRelDO;
import com.ibeeking.found.cop.service.common.param.GroupTagsBatchParam;
import com.ibeeking.found.cop.service.common.param.GroupTagsParam;
import com.ibeeking.found.cop.service.common.query.GroupPageQuery;
import com.ibeeking.found.cop.service.common.query.GroupTagsPageQuery;
import com.ibeeking.found.cop.service.common.query.GroupTagsQuery;
import com.ibeeking.found.cop.service.common.vo.GroupTagsVO;
import com.ibeeking.found.cop.service.common.vo.GroupVO;
import com.ibeeking.found.cop.service.mapper.GroupTagsMapper;
import com.ibeeking.found.cop.service.mapper.GroupTagsRelMapper;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.DataUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName GroupTagsServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-27 18:50
 **/
@Service
public class GroupTagsServiceImpl extends ServiceImpl<GroupTagsMapper, GroupTagsDO> implements IGroupTagsService {

    @Resource
    private GroupTagsMapper groupTagsMapper;

    @Resource
    private GroupTagsRelMapper groupTagsRelMapper;

    @Resource
    private IGroupService groupServiceImpl;

    @Override
    public List<GroupTagsVO> list(GroupTagsQuery query) {
        List<GroupTagsDO> entityDOS = groupTagsMapper.selectList(new LambdaQueryWrapper<GroupTagsDO>()
                .eq(query.getId() != null, GroupTagsDO::getId, query.getId())
                .eq(GroupTagsDO::getType, 0)
                .like(StringUtils.isNotBlank(query.getTagsName()), GroupTagsDO::getTagsName, query.getTagsName())
                .eq(query.getStatus() != null, GroupTagsDO::getStatus, query.getStatus())
                .orderByDesc(GroupTagsDO::getCreateTime)
        );
        List<GroupTagsVO> entityVOS =JsonUtils.jsonToList(entityDOS, GroupTagsVO.class);
        entityVOS.forEach(x -> {
            x.setStatusDesc(PublishStatusEnum.getName(x.getStatus()));
        });
        return entityVOS;
    }

    @Override
    public Page<GroupTagsVO> pageList(GroupTagsPageQuery pageQuery) {
        LambdaQueryWrapper<GroupTagsDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, GroupTagsDO::getId, pageQuery.getId())
                .eq(GroupTagsDO::getType, 0)
                .like(StringUtils.isNotBlank(pageQuery.getTagsName()), GroupTagsDO::getTagsName, pageQuery.getTagsName())
                .eq(pageQuery.getStatus() != null, GroupTagsDO::getStatus, pageQuery.getStatus())
                .orderByDesc(GroupTagsDO::getCreateTime);
        Page<GroupTagsDO> entityDOPages = groupTagsMapper.selectPage(new Page<GroupTagsDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
        Page<GroupTagsVO> entityVOPages = BeanUtil.convertPage(entityDOPages, GroupTagsVO.class);
        entityVOPages.getRecords().forEach(f ->{
            f.setStatusDesc(PublishStatusEnum.getName(f.getStatus()));
        });
        return entityVOPages;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeTagsBatch(GroupTagsBatchParam param, CurrentUser currentUser) {
        Integer addOrLess = param.getAddOrLess();
        if (AddOrLessEnum.ADD.getValue().equals(addOrLess)) {
            this.addTagsBatch(param, currentUser);
        } else if (AddOrLessEnum.LESS.getValue().equals(addOrLess)) {
            this.delTagsBatch(param, currentUser);
        } else {
            return false;
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addTagsBatch(GroupTagsBatchParam param, CurrentUser currentUser) {
        List<GroupTagsRelDO> groupTagsRelRsultDOS= new ArrayList<>();
        Integer type = param.getType();
        Set<Long> tagsIds = param.getTagsIds();
        List<Long> newGroupIds = param.getGroupIds();
        GroupPageQuery condition = param.getCondition();
        if(type!=null && type==2){
            if(condition!=null){
                Page<GroupVO> groupVOPage = groupServiceImpl.pageList(condition);
                if(groupVOPage!=null && groupVOPage.getSize() >0){
                    newGroupIds = groupVOPage.getRecords().stream().map(GroupVO::getId).collect(Collectors.toList());
                }else{
                    newGroupIds = Collections3.emptyList();
                }
            }
        }
        LogUtils.info("==== add newFriendsIds:{}========",JsonUtils.toJsonStr(newGroupIds));
        if(newGroupIds == null || newGroupIds.size() <=0) {
            throw new BusinessException("请至少选择一个群！");
        }
        if(tagsIds ==null && tagsIds.size() <= 0){
            throw new BusinessException("请至少选择一个标签！");
        }

        for(Long tagsId: tagsIds){
            List<GroupTagsRelDO> groupTagsRelDOS = groupTagsRelMapper.selectList(new LambdaQueryWrapper<GroupTagsRelDO>().eq(GroupTagsRelDO::getTagsId, tagsId));
            LogUtils.info("==== add friendsTagsRelDOS:{}========",JsonUtils.toJsonStr(groupTagsRelDOS));
            if (Collections3.isNotEmpty(groupTagsRelDOS)) {
                List<Long> oldGroupIds = groupTagsRelDOS.stream().map(GroupTagsRelDO::getGroupId).collect(Collectors.toList());
                LogUtils.info("==== add oldFriendsIds:{}========",JsonUtils.toJsonStr(oldGroupIds));
                HashSet<Long> olsHashGroupIds = new HashSet<>(oldGroupIds);
                LogUtils.info("==== add olsHashFriendsIds:{}========",JsonUtils.toJsonStr(olsHashGroupIds));
                HashSet<Long> newHashGroupIds = new HashSet<>(newGroupIds);
                LogUtils.info("==== add newHashFriendsIds:{}========",JsonUtils.toJsonStr(newHashGroupIds));
                newHashGroupIds.removeAll(olsHashGroupIds);
                LogUtils.info("==== add newHashFriendsIds remove:{}========",JsonUtils.toJsonStr(newHashGroupIds));
                if (newHashGroupIds != null && newHashGroupIds.size() > 0) {
                    newHashGroupIds.stream().forEach(f -> {
                        groupTagsRelRsultDOS.add(new GroupTagsRelDO(GenerateId.generateId(), f.longValue(), tagsId));
                    });
                }
            }else{
                if (newGroupIds != null && newGroupIds.size() > 0) {
                    newGroupIds.stream().forEach(f -> {
                        groupTagsRelRsultDOS.add(new GroupTagsRelDO(GenerateId.generateId(), f.longValue(), tagsId));
                    });
                }
            }
        };
        LogUtils.info("====friendsTagsRelRsultDOS:{}========",JsonUtils.toJsonStr(groupTagsRelRsultDOS));
        if(groupTagsRelRsultDOS !=null && groupTagsRelRsultDOS.size() >0){
            return groupTagsRelMapper.insertBatchSomeColumn(groupTagsRelRsultDOS) >0;
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean delTagsBatch(GroupTagsBatchParam param, CurrentUser currentUser) {
        List<Long> groupTagsRelIdS= new ArrayList<>();

        Integer type = param.getType();
        Set<Long> tagsIds = param.getTagsIds();
        List<Long> newGroupIds = param.getGroupIds();
        GroupPageQuery condition = param.getCondition();
        if(condition == null || condition.getTagsIds() == null || condition.getTagsIds().size() <=0) throw new BusinessException("必须基于标签条件筛选后才能统一删除标签！");
        LogUtils.info("====condition:{}========",JsonUtils.toJsonStr(condition));
        if(type!=null && type==2){
            Page<GroupVO> groupVOPage = groupServiceImpl.pageList(condition);
            if(groupVOPage!=null && groupVOPage.getSize() >0){
                newGroupIds = groupVOPage.getRecords().stream().map(GroupVO::getId).collect(Collectors.toList());
            }else{
                newGroupIds = Collections3.emptyList();
            }
        }
        if(newGroupIds == null || newGroupIds.size() <=0) {
            throw new BusinessException("请至少选择一个群！");
        }
        if(tagsIds ==null && tagsIds.size() <= 0){
            throw new BusinessException("请至少选择一个标签！");
        }
        LogUtils.info("====newFriendsIds:{}========",JsonUtils.toJsonStr(newGroupIds));
        for(Long tagsId: tagsIds){
            List<GroupTagsRelDO> groupTagsRelDOS = groupTagsRelMapper.selectList(new LambdaQueryWrapper<GroupTagsRelDO>()
                    .eq(GroupTagsRelDO::getTagsId, tagsId).in(GroupTagsRelDO::getGroupId,newGroupIds));
            if (Collections3.isNotEmpty(groupTagsRelDOS)) {
                List<Long> oldRelIds = groupTagsRelDOS.stream().map(GroupTagsRelDO::getId).collect(Collectors.toList());
                groupTagsRelIdS.addAll(oldRelIds);
            }
        };
        LogUtils.info("====friendsTagsRelIdS:{}========",JsonUtils.toJsonStr(groupTagsRelIdS));
        if(groupTagsRelIdS !=null && groupTagsRelIdS.size() >0){
            return groupTagsRelMapper.deleteBatchIds(groupTagsRelIdS) >0;
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(GroupTagsParam param) {
        checkUnique(param);
        GroupTagsDO entityDO = BeanUtil.convertBean(param, GroupTagsDO.class);
        entityDO.setId(GenerateId.generateId());
        entityDO.setCreateBy(UserUtils.getUserId());
        entityDO.setCreateTime(LocalDateTime.now());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupTagsMapper.insert(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addBatch(List<GroupTagsRelDO> addList) {
        if (Collections3.isEmpty(addList)) {
            return false;
        }
        List<Long> idList = addList.stream().map(GroupTagsRelDO::getId).collect(Collectors.toList());
        List<GroupTagsRelDO> oldList = groupTagsRelMapper.selectBatchIds(idList);
        if (Collections3.isNotEmpty(oldList)) {
            List<Long> oldIdList = oldList.stream().map(GroupTagsRelDO::getId).collect(Collectors.toList());
            addList.removeIf(x -> oldIdList.contains(x.getId()));
        }
        if (Collections3.isEmpty(addList)) {
            return true;
        }
        DataUtils.groupList(addList, FriendsConstant.BATCH_SIZE).forEach(inList -> {
            groupTagsRelMapper.insertBatchSomeColumn(inList);
        });
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(GroupTagsParam param) {
        GroupTagsDO entityDO = BeanUtil.convertBean(param, GroupTagsDO.class);
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupTagsMapper.updateById(entityDO) > 0;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateBatch(List<GroupTagsDO> entityDOS) {
        return super.updateBatchById(entityDOS);
    }

    @Override
    public GroupTagsVO view(Long id) {
        GroupTagsDO entityDO = groupTagsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        GroupTagsVO entityVO = BeanUtil.convertBean(entityDO, GroupTagsVO.class);
        if(entityVO != null) {
            entityVO.setStatusDesc(PublishStatusEnum.getName(entityDO.getStatus()));
        }
        return entityVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeStatus(Long id, Integer status) {
        GroupTagsDO entityDO = groupTagsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        entityDO.setStatus(status);
        entityDO.setModifyBy(UserUtils.getUserId());
        entityDO.setModifyTime(LocalDateTime.now());
        return groupTagsMapper.updateById(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean del(Long id) {
        GroupTagsDO entityDO = groupTagsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        return groupTagsMapper.deleteById(id) > 0;
    }
    /**
     * 校验唯一性
     *
     * @param param
     */
    public void checkUnique(GroupTagsParam param) {
        if (param == null) {
            throw new BusinessException("当前记录不存在!");
        }
        //code name确保等级唯一性
        LambdaQueryWrapper<GroupTagsDO> queryWrapper = new LambdaQueryWrapper<GroupTagsDO>()
                .ne(param.getId() != null, GroupTagsDO::getId, param.getId())
                .eq(GroupTagsDO::getTagsName, param.getTagsName());
        List<GroupTagsDO> dos = groupTagsMapper.selectList(queryWrapper);
        if (Collections3.isNotEmpty(dos)) {
            throw new BusinessException("已经存在同名的记录!");
        }
    }

}
